;; protocol/osc-transport.scm - (c) rohan drape, 2004-2005

;; An OSC transport mechanism that can operate over UDP and TCP.

(define-structure osc-transport (sender disconnecter address timeout))

;; The address is a <network-address> value.  The timeout is a <real>
;; value given in seconds, or #f for indefinite wait.  The mechanism
;; is a <symbol>.

(defineV make-osc-transport
  (lambdaK ((address #f) (timeout 1) (mechanism 'udp))
    (define (receiver network-address packet)
      (osc-receiver-dispatch packet)
      (osc-responder-dispatch packet))
    (if (eq? mechanism 'tcp)
	(let ((t (make-tcp-client address receiver)))
	  (make-osc-transport* (lambda (packet) (tcp-client-send t packet))
			       (lambda () (tcp-client-stop t))
			       address
			       timeout))
	(let ((u (make-udp-client address receiver)))
	  (make-osc-transport* (lambda (packet) (udp-client-send u packet))
			       (lambda () (udp-client-stop u))
			       address
			       timeout)))))
  
(define (osc-send-u8vector t u8vector)
  ((osc-transport-sender t) u8vector))

(define (osc-send t packet)
  (osc-send-u8vector t (osc-encode-packet (osc-purify packet))))

(define (osc-send-message t message)
  (osc-send-u8vector t (osc-encode-message (osc-purify message))))

(define (osc-send-bundle t bundle)
  (osc-send-u8vector t (osc-encode-bundle (osc-purify bundle))))

;; This procedure does *NOT* ensure that it is not called from the
;; <osc-transport> thread, which would lead to a deadlock.

(define (osc-request t return message)
  (let* ((semaphore (make-semaphore))
	 (result #f)
	 (receiver (lambda (packet) 
		     (set! result packet)
		     (semaphore-post semaphore))))
    (osc-receiver-register return receiver)
    (osc-send-message t message)
    (semaphore-wait/timeout (osc-transport-timeout t) semaphore)
    (osc-receiver-unregister receiver)
    result))

(define (osc-transport-stop t)
  ((osc-transport-disconnecter t)))

